
#ifndef _TTG_DEVICES_GPU_GPU_
#define _TTG_DEVICES_GPU_GPU_
#include "Common/Definitions.h"

#include "Runtime.Low/Devices/IdManager.h"
#include "CUDA/CudaManager.h"

namespace ttg
{
	namespace devices
	{
		//Definition of GPU device (that can be unavailable due to poor functionality).
		class GPU :public Device
		{
			private:
				static GPU *ref;
				//Creates instance.
				static inline void safeInit()
				{
					if (ref == NULL)
						ref = new GPU();
				}
				//Creates GPU-device and registers it.
				inline GPU()
					:Device("GPU",
							ttg_internal::devices::IdManager::getRef()->generateDeviceID())
				{ /*nothing*/ }
			public:
				//Returns instance of GPU-device.
				static inline GPU *getRef()
				{ safeInit(); return ref; }
			//Defenition of the known APIs.

				//NVidia, the way it's meant to be COMPUTED!
				class CUDA :public Api
				{
					private:
						static CUDA *ref;
						//Creates instance.
						static inline void safeInit()
						{
							if (ref == NULL)
								ref = new CUDA();
						}
					private:
						ttg_internal::devices::CudaManager *manager;
						//Creates and registers API for NVidia CUDA.
						inline CUDA()
							:Api("CUDA",
								 ttg_internal::devices::IdManager::getRef()->generateApiID(GPU::getRef()->getID()),
								 GPU::getRef())
						{ manager = new ttg_internal::devices::CudaManager(); }
					public:
						//Performs required action in the CUDA thread.
						//Note: "action" will be released.
						inline void perform(ttg::structures::InvokableObject *action)
						{ manager->perform(action); }
						//Returns true, if API is available on this machine.
						virtual bool isAvailable()
						{ return manager->isAvailable(); }
						//Returns true, if additional CPU-thread is requred.
						//It means, that corresponded task will use CPU-thread as well as this device.
						virtual bool isAccelerator()
						{ return true; }
						//Returns count of tasks, that can be executed simultaneously via this API.
						virtual size_t getConcurrencyLevel()
						{ return manager->getCount(); }
						//Returns instance of CUDA API.
						static inline CUDA *getRef()
						{ safeInit(); return ref; } 
						//Returns type for logical CUDA-device.
						static inline LogicalDevice getType()
						{ return LogicalDevice(GPU::getRef()->getID(), GPU::CUDA::getRef()->getID()); }
				};
		};
	}
}

#endif
